//
//  AsyncImageView.m
//  Postcard
//
//  Created by markj on 2/18/09.
//  Copyright 2009 Mark Johnson. You have permission to copy parts of this code into your own projects for any use.
//  www.markj.net
//

#import "AsyncImageView.h"
#import "CmnMacro.h"
#import "LocalURLCache.h"

// This class demonstrates how the URL loading system can be used to make a UIView subclass
// that can download and display an image asynchronously so that the app doesn't block or freeze
// while the image is downloading. It works fine in a UITableView or other cases where there
// are multiple images being downloaded and displayed all at the same time.

@interface AsyncImageView ()

@property (nonatomic, copy) NSURL * cacheURL;

@end

@implementation AsyncImageView

@synthesize delegate = _delegate;
@synthesize cacheURL = _cacheURL;

- (void)dealloc {
	if (connection)
		[connection cancel]; //in case the URL is still downloading
	SAFE_RELEASE(connection);
	SAFE_RELEASE(receivedata);
	SAFE_RELEASE(_url);
	SAFE_RELEASE(_cacheURL);
	SAFE_RELEASE(_aiView);
	self.delegate = nil;
    [super dealloc];
}

- (void)awakeFromNib
{
	[super awakeFromNib];

	tryTimes = 0;
	_url = nil;
}

- (void)setImage:(UIImage *)image
{
	[super setImage:image];
	
	if (_aiView)
	{
		[_aiView stopAnimating];
	}
}

#define MAX_TRY_TIMES 3

- (void)tryAgainMethod:(NSTimer*)theTimer
{
	if (tryTimes < MAX_TRY_TIMES)
	{
		[self loadImageFromURL:_url withCacheURL:self.cacheURL showLoading:NO];
	}
	else
	{
		tryTimes = 0;
		if (_aiView)
		{
			[_aiView stopAnimating];
		}
	}
}

- (void)tryAgain
{
	[NSTimer scheduledTimerWithTimeInterval:1.0
									 target:self
								   selector:@selector(tryAgainMethod:)
								   userInfo:nil
									repeats:NO];
}

- (void)loadImageFromURL:(NSURL*)url showLoading:(BOOL)bShow{

	if (_url != url)
	{
		SAFE_RELEASE(_url);
		SAFE_RELEASE(_cacheURL);
		_url = [url retain];
	}
	
	if (bShow && !_aiView)
	{
		_aiView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
		[self addSubview:_aiView];
		_aiView.center = [self.superview convertPoint:self.center toView:_aiView];
		_aiView.hidesWhenStopped = YES;
	}
	
	if (connection != nil)
	{
		[connection cancel];
		tryTimes = 0;
	} //in case we are downloading a 2nd image
	
	tryTimes++;
	
	SAFE_RELEASE(connection);
	SAFE_RELEASE(receivedata);
	
	NSString * cachedFile = [[LocalURLCache sharedLocalURLCache] cachedFileWithURL:self.cacheURL];
	if ([[NSFileManager defaultManager] fileExistsAtPath:cachedFile])
	{
		self.image = [UIImage imageWithContentsOfFile:cachedFile];
		if (self.image)
		{
			if (self.delegate && [self.delegate respondsToSelector:@selector(DidFinishLoadImage)]) {
				[self.delegate DidFinishLoadImage];
			}
			
			return;
		}
	}
	
	if (_aiView)
	{
		bShow ? [_aiView startAnimating] : [_aiView stopAnimating];
	}
	
	NSURLRequest* request = [NSURLRequest requestWithURL:_url cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:60.0];
	connection = [[NSURLConnection alloc] initWithRequest:request delegate:self]; //notice how delegate set to self object
	//TODO error handling, what if connection is nil?
}

- (void)loadImageFromURL:(NSURL*)url
{
	[self loadImageFromURL:url withCacheURL:nil showLoading:NO];
}

- (void)loadImageFromURL:(NSURL*)url withCacheURL:(NSURL *)cacheURL showLoading:(BOOL)bShow
{
	if (self.cacheURL != cacheURL)
		self.cacheURL = cacheURL;
	
	[self loadImageFromURL:url showLoading:bShow];
}

//the URL connection calls this repeatedly as data arrives
- (void)connection:(NSURLConnection *)theConnection didReceiveData:(NSData *)incrementalData {
	if (receivedata==nil) { receivedata = [[NSMutableData alloc] initWithCapacity:2048]; } 
	[receivedata appendData:incrementalData];
}

//the URL connection calls this once all the data has downloaded
- (void)connectionDidFinishLoading:(NSURLConnection*)theConnection {
	//so self data now has the complete image 
	self.image = [UIImage imageWithData:receivedata];
	if (self.image)
	{
		[[LocalURLCache sharedLocalURLCache] cacheData:receivedata withURL:self.cacheURL];
	}

	SAFE_RELEASE(connection);
	SAFE_RELEASE(receivedata);
	
	if (self.delegate && [self.delegate respondsToSelector:@selector(DidFinishLoadImage)]) {
		[self.delegate DidFinishLoadImage];
	}
}

- (void)connection:(NSURLConnection *)theConnection didFailWithError:(NSError *)error
{
	SAFE_RELEASE(connection);
	SAFE_RELEASE(receivedata);

	[self tryAgain];
}

- (NSURL *)cacheURL
{
	if (_cacheURL == nil)
	{
		_cacheURL = [_url copy];
	}
	
	return _cacheURL;
}

@end
